package com.mingqijia.gassafety.job.job.warnStrategy;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gap.cache.redis.RedisCache;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.util.StringUtil;
import com.mingqijia.gassafety.db.entity.BusinessNotice;
import com.mingqijia.gassafety.db.entity.Consumer;
import com.mingqijia.gassafety.db.entity.CustomerSubs;
import com.mingqijia.gassafety.db.entity.DeviceState;
import com.mingqijia.gassafety.db.entity.Dtu;
import com.mingqijia.gassafety.db.entity.DtuBindingOrder;
import com.mingqijia.gassafety.db.entity.JvInfo;
import com.mingqijia.gassafety.db.entity.ReceiverValve;
import com.mingqijia.gassafety.db.entity.RecordReceiverValve;
import com.mingqijia.gassafety.db.entity.WarnStrategy;
import com.mingqijia.gassafety.db.entity.WarnStrategyExt;
import com.mingqijia.gassafety.db.entity.WarningRecord;
import com.mingqijia.gassafety.db.mapper.BusinessNoticeMapper;
import com.mingqijia.gassafety.db.mapper.ConsumerMapper;
import com.mingqijia.gassafety.db.mapper.ContactsMapper;
import com.mingqijia.gassafety.db.mapper.CustomerSubsMapper;
import com.mingqijia.gassafety.db.mapper.DeviceStateMapper;
import com.mingqijia.gassafety.db.mapper.DictionaryMapper;
import com.mingqijia.gassafety.db.mapper.DtuBindingOrderMapper;
import com.mingqijia.gassafety.db.mapper.DtuMapper;
import com.mingqijia.gassafety.db.mapper.JvInfoMapper;
import com.mingqijia.gassafety.db.mapper.ReceiverValveMapper;
import com.mingqijia.gassafety.db.mapper.RecordReceiverValveMapper;
import com.mingqijia.gassafety.db.mapper.WarnStrategyExtMapper;
import com.mingqijia.gassafety.db.mapper.WarnStrategyMapper;
import com.mingqijia.gassafety.db.mapper.WarningRecordMapper;
import com.mingqijia.gassafety.job.dto.PredateStrategyDTO;
import com.mingqijia.gassafety.job.dto.SendMessageDTO;
import com.mingqijia.gassafety.job.service.ConsumerService;
import com.mingqijia.gassafety.job.service.impl.CallTaskServiceImpl;
import com.mingqijia.gassafety.job.service.impl.CompanyServiceImpl;
import com.mingqijia.gassafety.job.service.impl.DevicebindingServiceImpl;
import com.mingqijia.gassafety.job.service.impl.EquipmentServiceImpl;
import com.mingqijia.gassafety.job.service.impl.WarningRecordServiceImpl;
import com.mingqijia.gassafety.job.strategy.MessageContext;
import com.mingqijia.gassafety.job.strategy.PredicateGasWarnContext;
import com.mingqijia.gassafety.job.strategy.RecordService;
import com.mingqijia.gassafety.shared.constant.Constants;
import com.mingqijia.gassafety.shared.constant.DeviceStatusEnum;
import com.mingqijia.gassafety.shared.constant.EquipmentType;
import com.mingqijia.gassafety.shared.constant.EquipmentTypeConst;
import com.mingqijia.gassafety.shared.constant.PushTypeEnum;
import com.mingqijia.gassafety.shared.constant.SignalEnum;
import com.mingqijia.gassafety.shared.dto.AssembleTemplateDTO;
import com.mingqijia.gassafety.shared.utils.RedisCacheExt;
import com.mingqijia.gassafety.shared.utils.commonUtils.SnowflakeUtil;
import com.mingqijia.gassafety.shared.utils.message.SendMessageService;
import com.mingqijia.gassafety.shared.vcc.VccAuthoritiesProvider;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.log.XxlJobLogger;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ConvertingCursor;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

/**
 * @author zhangfei
 * @version 1.0.0
 * @ClassName WarnStrategyV2Job.java
 * @Description
 * @createTime 2022年02月28日
 */

@Component
@Slf4j
public class WarnStrategyV2Job {

    @Autowired
    RedisCache redisCache;
    @Autowired
    ConsumerMapper consumerMapper;
    @Autowired
    CustomerSubsMapper customerSubsMapper;
    @Autowired
    DtuMapper dtuMapper;
    @Autowired
    WarnStrategyExtMapper warnStrategyExtMapper;
    @Autowired
    ContactsMapper contactsMapper;
    @Autowired
    SendMessageService sendMessageService;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    DictionaryMapper dictionaryMapper;
    @Autowired
    WarnStrategyMapper warnStrategyMapper;
    @Autowired
    WarningRecordMapper warningRecordMapper;
    @Autowired
    WarningRecordServiceImpl warningRecordService;
    @Autowired
    EquipmentServiceImpl equipmentService;
    @Autowired
    CompanyServiceImpl companyService;

    @Autowired
    DevicebindingServiceImpl devicebindingService;
    @Autowired
    BusinessNoticeMapper noticeMapper;

    @Autowired
    ReceiverValveMapper receiverValveMapper;


    @Autowired
    MessageContext messageContext;

    @Autowired
    PredicateGasWarnContext predicateGasWarnContext;

    @Autowired
    RecordService warnRecordService;


    public static final String split = ";";
    public static final String split_ = "-";

    //需要匹配的key
    private String patternKey = Constants.WARNING_EQUIPMENT + ":*";

    public static final String CM_SERVICE_HOT_LINE="cm_service_hot_line";

    public static final Integer pageSize = 1000;

    @Value(value = "${gassafety.warnStrategy.switch}")
    private boolean sw;
    @Autowired
    RedisCacheExt redisUtil;

    @Autowired
    VccAuthoritiesProvider provider;

    @Autowired
    DeviceStateMapper deviceStateMapper;
    @Autowired
    DtuBindingOrderMapper dtuBindingOrderMapper;
    @Autowired
    ConsumerService consumerService;
    @Autowired
    CallTaskServiceImpl callTaskService;
    @Autowired
    RecordReceiverValveMapper  recordReceiverValveMapper;

    @Autowired
    JvInfoMapper jvInfoMapper;

    /**
     * 燃气泄漏报警策略 再次预警: 一分钟一次：0 0/1 * * * ?
     */
    @XxlJob("warnStrategyAgain")
    public ReturnT<String> warnStrategyAgain(String param) {
        XxlJobLogger.log("XXLJOB-warnStrategyAgain start..." );
        log.info("warnStrategyAgain--start--------");

        // 燃气泄漏报警策略开关
        if (!sw) return ReturnT.SUCCESS;
        // 燃气泄漏报警策略再次预警job锁
        String redisKey = Constants.EQUIPMENT_WARNING_AGAIN;
        try {
            Boolean acquire = redisUtil.setIfAbsent(redisKey, String.valueOf(System.currentTimeMillis()), Constants.TIME_OUT);//15分钟超时
            if (acquire) {
                try {
                    List<String> keys = getKeys(redisTemplate, patternKey);
                    if (!CollectionUtil.isEmpty(keys)) {
                        log.info("warnStrategyAgain-本次扫描到需要执行的数据：{}", JSONObject.toJSONString(keys));
                        //进行再次预警
                        for (String key : keys) {
                            try {
                                // 执行报警策略所需要的数据
                                PredateStrategyDTO predateStrategyDTO = new PredateStrategyDTO();

                                // 组装执行报警策略所需要的基础数据
                                if (!setBaseData(predateStrategyDTO, key)) {
                                    continue;
                                }

                                // 判断报警数据是否正常，是否会报警
                                if (!predicateWarnData(predateStrategyDTO)) {
                                    continue;
                                }

                                // 可以发送的数据列表
                                List<SendMessageDTO> sendDataList = new ArrayList<>();

                                // 判断低报，高报，正常
                                // 低报策略
                                predicateGasWarnContext.getPredicateGasWarnStrategy("predicateGasLowWarnStrategy").predicateGasWarn(predateStrategyDTO.getWarnStrategy(), predateStrategyDTO.getWarnStrategyExtList(), predateStrategyDTO.getCacheMap(), sendDataList, predateStrategyDTO);
                                // 高报策略
                                predicateGasWarnContext.getPredicateGasWarnStrategy("predicateGasHighWarnStrategy").predicateGasWarn(predateStrategyDTO.getWarnStrategy(), predateStrategyDTO.getWarnStrategyExtList(), predateStrategyDTO.getCacheMap(), sendDataList, predateStrategyDTO);
                                // 正常策略
                                predicateGasWarnContext.getPredicateGasWarnStrategy("predicateGasNormalWarnStrategy").predicateGasWarn(predateStrategyDTO.getWarnStrategy(), predateStrategyDTO.getWarnStrategyExtList(), predateStrategyDTO.getCacheMap(), sendDataList, predateStrategyDTO);

                                // 消息发送
                                if (CollectionUtils.isNotEmpty(sendDataList)) {
                                    // 发送本地消息
                                    messageContext.getMessageStrategy("sendLocalMessageStrategy").sendMessage(sendDataList, "warnStrategyAgain", warnRecordService);
                                    // 发送短信
                                    messageContext.getMessageStrategy("sendSmsMessageStrategy").sendMessage(sendDataList, "warnStrategyAgain", warnRecordService);
                                    // 发送微信消息
                                    messageContext.getMessageStrategy("sendWxMessageStrategy").sendMessage(sendDataList, "warnStrategyAgain", warnRecordService);
                                    // 发送机器人外呼消息
                                    messageContext.getMessageStrategy("sendCallMessageStrategy").sendMessage(sendDataList, "warnStrategyAgain", warnRecordService);

                                }
                                // 保存最新的燃气泄漏报警缓存数据到redis
                                if (predateStrategyDTO.isSaveCache()) {
                                    log.info("warnStrategyAgain-缓存数据-key：{},value：{}", predateStrategyDTO.getKey(),
                                        JSONObject.toJSONString(predateStrategyDTO.getCacheMap()));
                                    redisCache.setCacheMap(key, predateStrategyDTO.getCacheMap());
                                }

                            } catch(Exception e) {
                                log.error("error",e);
                            }
                        }
                    }
                } catch (NumberFormatException e) {
                    log.info("warnStrategyAgain-error:{}", e);
                } finally {
                    redisUtil.del(redisKey);
                }
            }
        } catch (Exception e) {
            log.info("warnStrategyAgain-error:{}", e);
        }
        log.info("warnStrategyAgain--end--------");
        XxlJobLogger.log("XXLJOB-warnStrategyAgain end..." );
        return ReturnT.SUCCESS;
    }

    public boolean setBaseData(PredateStrategyDTO predateStrategyDTO, String key) {
        predateStrategyDTO.setSaveCache(true);
        // 获取燃气泄漏报警缓存
        Map<String, Object> cacheMap = redisCache.getCacheMap(key);
        if (cacheMap == null) {
            return false;
        }
        log.info("warnStrategyAgain-cacheMap:{}", JSONObject.toJSONString(cacheMap));
        predateStrategyDTO.setCacheMap(cacheMap);
        String imei = cacheMap.get("iMEI").toString(); // 完整的IMEI
        String superImei = imei.toString().split("-")[0]; // 获取主体的IMEI
        predateStrategyDTO.setSuperImei(superImei);
        predateStrategyDTO.setImei(imei);
        // 查询设备信息
        Dtu dtu = dtuMapper.selectByImei(predateStrategyDTO.getSuperImei(), null); //查找绑定了客户的设备
        if (dtu == null) {
            log.info("warnStrategyAgain-设备信息不存在或未绑定客户:{}", predateStrategyDTO.getSuperImei());
            deleteCache(predateStrategyDTO, predateStrategyDTO.getCacheMap().get("identificationCode").toString());
            return false;
        }
        predateStrategyDTO.setDtu(dtu);
        cacheMap.put("spId", dtu.getSpId());
        predateStrategyDTO.setSpId(dtu.getSpId());// 企业spId
        String subImei = imei;
        if (imei.contains(split_)) {
            // 包含-的都是气体报警控制器下的点型可燃气体探测器  XXX-X-X
            subImei = superImei + "-" + imei.split(split_)[1] + "-" + imei.split(split_)[2];
        } else {
            // 不包含-
            // 气体报警控制器的数据不需要，只需要他下面的点型可燃气体控制器
            if (!EquipmentType.GAS_ALARM_CONTROLLER.getCode().equals(dtu.getEquipmentType())) {
                subImei = superImei + "-1-0";
            }
        }
        predateStrategyDTO.setSubImei(subImei);
        // predateStrategyDTO.setSpId(cacheMap.get("spId").toString());// 企业spId
        predateStrategyDTO.setKey(key); // 燃气泄漏报警信息缓存
        predateStrategyDTO.setAlarmStrategykey(imei + predateStrategyDTO.getSpId());

        // 策略信息
        predateStrategyDTO.setStrategyId((Long)cacheMap.get("strategyId"));

        // 时间信息
        predateStrategyDTO.setDate(new Date());
        predateStrategyDTO.setNowTime(predateStrategyDTO.getDate().getTime());

        // 公共信息
        // 公共信息-公司名称
        String orgName = Constants.BLANK;
        QueryWrapper<JvInfo> jvInfoQuery = new QueryWrapper<>();
        jvInfoQuery.lambda().or().eq(JvInfo::getIsDeleted, 0)
            .eq(JvInfo::getSpId, predateStrategyDTO.getSpId());
        List<JvInfo> jvInfo = jvInfoMapper.selectList(jvInfoQuery);
        if (!CollectionUtil.isEmpty(jvInfo)) orgName = jvInfo.get(0).getName();
        predateStrategyDTO.setOrgName(orgName);
        // 公共信息-公司电话
        QueryWrapper<BusinessNotice> query = new QueryWrapper<>();
        query.lambda().or().eq(BusinessNotice::getIsDeleted, 0)
            .eq(BusinessNotice::getSpId, predateStrategyDTO.getSpId())
            .eq(BusinessNotice::getParamCode, CM_SERVICE_HOT_LINE);
        List<BusinessNotice> r = noticeMapper.selectList(query);
        String phone = Constants.BLANK;
        if (!CollectionUtil.isEmpty(r)) phone = r.get(0).getParamValue();
        predateStrategyDTO.setOrgPhone(phone);
        // 公共信息-本次发送标识
        predateStrategyDTO.setSnowflakeId(Long.parseLong(predateStrategyDTO.getCacheMap().get("identificationCode").toString()));
        return true;
    }

    public boolean predicateWarnData(PredateStrategyDTO predateStrategyDTO) {

        // 判断报警器设备状态信息是否存在，是否离线
        DeviceState deviceState = deviceStateMapper.selectByDeviceId(predateStrategyDTO.getImei(), predateStrategyDTO.getDtu().getSpId());
        if (deviceState == null || deviceState.getDeviceStatus() == null || deviceState.getDeviceStatus() == 0) {
            log.info("warnStrategyAgain-设备已经离线:{}", predateStrategyDTO.getSubImei());
            deleteCache(predateStrategyDTO, predateStrategyDTO.getCacheMap().get("identificationCode").toString());
            return false;
        }

        Integer value = deviceState.getConcentration() == null ? 0 : deviceState.getConcentration();
        predateStrategyDTO.setValue(value);

        //查询客户信息
        Integer consumerId = predateStrategyDTO.getDtu().getConsumerId();
        Consumer consumer = warnStrategyMapper.selectIndustry(consumerId, predateStrategyDTO.getImei());
        predateStrategyDTO.setConsumer(consumer);
        // 查询策略是否还存在，是否还是启用中
        WarnStrategy warnStrategy = warnStrategyMapper.selectById(predateStrategyDTO.getStrategyId());
        if (warnStrategy == null || warnStrategy.getIsDeleted() || warnStrategy.getIsDisabled() == 1) {
            log.info("warnStrategyAgain-报警策略已关闭或删除：{}", predateStrategyDTO.getImei());
            deleteCache(predateStrategyDTO, predateStrategyDTO.getCacheMap().get("identificationCode").toString());
            return false;
        }
        predateStrategyDTO.setWarnStrategy(warnStrategy);

        // 查询策略明细
        QueryWrapper<WarnStrategyExt> warnStrategyExtQueryWrapper = new QueryWrapper<>();
        warnStrategyExtQueryWrapper.lambda().eq(WarnStrategyExt::getIsDeleted, 0)
                .eq(WarnStrategyExt::getStrategyId, predateStrategyDTO.getStrategyId())
                .orderByAsc(WarnStrategyExt::getSort);
        List<WarnStrategyExt> warnStrategyExtList = warnStrategyExtMapper.selectList(warnStrategyExtQueryWrapper);
        predateStrategyDTO.setWarnStrategyExtList(warnStrategyExtList);

        Integer status = (deviceState.getDeviceStatus() == null) ? 0 : deviceState.getDeviceStatus();
        if (warnStrategy.getCheckDeviceState() != null && warnStrategy.getCheckDeviceState() == 1
                && (status != 2 && status != 3 && status != 6)) {//状态非低报，高报，报警
            log.info("warnStrategyAgain-是否检验报警状态:{},设备状态为未报警:{},{}",
                    warnStrategy.getCheckDeviceState(), predateStrategyDTO.getImei(), status);
            deleteCache(predateStrategyDTO, predateStrategyDTO.getCacheMap().get("identificationCode").toString());
            return false;
        }

        return true;
    }

    public static List<String> getKeys(RedisTemplate redisTemplate, String patternKey) {
        long start = System.currentTimeMillis();
        List<String> result = new ArrayList<>();
        try {
            ScanOptions options = ScanOptions.scanOptions()
                .count(1000)
                .match(patternKey).build();
            RedisSerializer<String> redisSerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
            Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redisConnection ->
                    new ConvertingCursor<>(redisConnection.scan(options), redisSerializer::deserialize));
            while (cursor.hasNext()) {
                result.add(cursor.next().toString());
            }
            cursor.close();
        } catch (IOException e) {
            log.error("getKeys-error:{}", e);
            return result;
        }
        log.info("scan扫描共耗时：{} ms key数量：{}", System.currentTimeMillis() - start, result.size());
        return result;
    }

    public void deleteCache(PredateStrategyDTO predateStrategyDTO, String identificationCode) {
        predateStrategyDTO.setSaveCache(false);
        redisCache.deleteObject(predateStrategyDTO.getKey());
        log.info("warnStrategyAgain-删除队列中的key：{}", predateStrategyDTO.getKey());
        //更新数据
        warningRecordService.updateRecordStatus(predateStrategyDTO.getImei(), identificationCode, 2);
        //删除策略执行次数key
        redisCache.deleteObject(Constants.ALARM_STRATEGY + predateStrategyDTO.getAlarmStrategykey());
        log.info("warnStrategyAgain-删除队列中的策略计数key：{}", "alarm_strategy" + predateStrategyDTO.getAlarmStrategykey());
    }


}
